﻿using IronBefunge.Core.InstructionHandlers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace IronBefunge.Core.Tests.InstructionHandlers
{
	[TestClass]
	public sealed class TurnInstructionHandlerTests : InstructionHandlerTests
	{
		internal override ReadOnlyCollection<char> GetExpectedHandledInstructions()
		{
			return new List<char>() { TurnInstructionHandler.LeftRightInstruction,
				TurnInstructionHandler.UpDownInstruction }.AsReadOnly();
		}

		internal override Type GetHandlerType()
		{
			return typeof(TurnInstructionHandler);
		}

		[TestMethod]
		public void HandleGoingDown()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), TurnInstructionHandler.UpDownInstruction) };

			var stackCount = 0;

			InstructionHandlerTests.Run(new TurnInstructionHandler(), cells, (context) =>
				{
					context.Values.Push(0);
					stackCount = context.Values.Count;
				}, (context, result) =>
				{
					Assert.AreEqual(stackCount - 1, context.Values.Count);
					Assert.AreEqual(Direction.Down, context.Direction);
				});
		}

		[TestMethod]
		public void HandleGoingDownOrUpWithEmptyStack()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), TurnInstructionHandler.UpDownInstruction) };

			var stackCount = 0;

			InstructionHandlerTests.Run(new TurnInstructionHandler(), cells, (context) =>
				{
					stackCount = context.Values.Count;
				}, (context, result) =>
				{
					Assert.AreEqual(stackCount, context.Values.Count);
					Assert.AreEqual(Direction.Down, context.Direction);
				});
		}
		
		[TestMethod]
		public void HandleGoingLeft()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), TurnInstructionHandler.LeftRightInstruction) };

			var stackCount = 0;

			InstructionHandlerTests.Run(new TurnInstructionHandler(), cells, (context) =>
				{
					context.Values.Push(3);
					stackCount = context.Values.Count;
				}, (context, result) =>
				{
					Assert.AreEqual(stackCount - 1, context.Values.Count);
					Assert.AreEqual(Direction.Left, context.Direction);
				});
		}

		[TestMethod]
		public void HandleGoingLeftOrRightWithEmptyStack()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), TurnInstructionHandler.LeftRightInstruction) };

			var stackCount = 0;

			InstructionHandlerTests.Run(new TurnInstructionHandler(), cells, (context) =>
				{
					stackCount = context.Values.Count;
				}, (context, result) =>
				{
					Assert.AreEqual(stackCount, context.Values.Count);
					Assert.AreEqual(Direction.Right, context.Direction);
				});
		}

		[TestMethod]
		public void HandleGoingRight()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), TurnInstructionHandler.LeftRightInstruction) };

			var stackCount = 0;

			InstructionHandlerTests.Run(new TurnInstructionHandler(), cells, (context) =>
				{
					context.Values.Push(0);
					stackCount = context.Values.Count;
				}, (context, result) =>
				{
					Assert.AreEqual(stackCount - 1, context.Values.Count);
					Assert.AreEqual(Direction.Right, context.Direction);
				});
		}

		[TestMethod]
		public void HandleGoingUp()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), TurnInstructionHandler.UpDownInstruction) };

			var stackCount = 0;

			InstructionHandlerTests.Run(new TurnInstructionHandler(), cells, (context) =>
				{
					context.Values.Push(3);
					stackCount = context.Values.Count;
				}, (context, result) =>
				{
					Assert.AreEqual(stackCount - 1, context.Values.Count);
					Assert.AreEqual(Direction.Up, context.Direction);
				});
		}
	}
}
